/***************************************************************************
 *   Copyright (C) 2007 by saa   *
 *   root@saa   *
 ***************************************************************************/

#include "utils.h"

#include <QRegExp>
#include <QHostAddress>
#include <QHostInfo>
#include <QDebug>
#include <QtSql>

#define IP_4_SIZE 32

std::list<unsigned long> cidr2hosts(const unsigned long network, const unsigned int mask)
{
    std::list<unsigned long> result;
    unsigned int c_mask(IP_4_SIZE - mask);
    if(c_mask > 0) {
        unsigned long begin((network >> c_mask) << c_mask);
        unsigned long end(((0xffffffff << mask) >> mask) | network);
        for (; begin <= end; ++begin)
            result.push_back(begin);
    } else if(!c_mask)
        result.push_back(network);
    else
        ; //(c_mask < 0)  TODO some log info
    return result;
}


//another way, taken from iptables-save.c
#define IP_PARTS_NATIVE(n)      \
(unsigned int)((n)>>24)&0xFF,   \
(unsigned int)((n)>>16)&0xFF,   \
(unsigned int)((n)>>8)&0xFF,    \
(unsigned int)((n)&0xFF)

#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))


bool checkForIP( const QString & ipAddress )
{
    QString Octet = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])";
    QRegExp ipPattern("^" + Octet + "\\." + Octet + "\\." + Octet + "\\." + Octet + "$"); // i.e. the octets can be from 0-199 or 200-249 or 250-255
    if(ipPattern.indexIn(ipAddress) == -1)
        return false;
    return true;
}

QPair<QString,QString> checkForIPRange( const QString & target)
{
    QString Octet = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])";
    QRegExp cidrPattern("^(" + Octet + "\\." + Octet + "\\." + Octet + "\\." + Octet + ")(/)((?:[1-9]|[1-2][0-9]|3?[0-2]))$");
    cidrPattern.indexIn(target);
    QPair<QString,QString> result(qMakePair(cidrPattern.cap(1), cidrPattern.cap(3)));
    return result;
}

QStringList checkTargetList(const QStringList & targetList)
{
    QStringList result;
    for(int i = 0; i < targetList.size(); ++i)
        result += checkTarget(targetList.at(i));
    return result;
}


//only spelling check
QStringList checkTarget(const QString & target)
{
    QStringList result;
    if(checkForIP(target)) // simple IP
        result.append(target);
    else { // IP range
        QPair<QString,QString> ipRange = checkForIPRange(target);
        if(!ipRange.first.isEmpty() && !ipRange.second.isEmpty()){
            QHostAddress netAddress(ipRange.first);
            unsigned long decimalNetAddress(netAddress.toIPv4Address());
            unsigned long networkMask(ipRange.second.toUInt());
            std::list<unsigned long> hosts(cidr2hosts(decimalNetAddress, networkMask));
            for(std::list<unsigned long>::iterator it = hosts.begin(); it != hosts.end(); ++it)
                result.append(QHostAddress(*it).toString());
        }
        else {
            //TODO check is host name correct
            result.append(target);
        }
    }
    return result;
}

QStringList checkTargetListByHostName(const QStringList & targetList)
{
    QStringList result;
    QSqlQuery query;
    QString queryString;
    
    for(int i= 0; i < targetList.size(); ++i){
        QHostInfo hostInfo(QHostInfo::fromName (targetList.at(i)));
        if(targetList.at(i) != hostInfo.hostName())
            result.append(targetList.at(i));
    }
    return result;
}
